#include "vec2.h"

namespace GeorgeLib
{

	// constructor : an empty vector, (0,0,0)
	vec2::vec2() :
		x(0), y(0) {}

	// constructor : from three values, (x,y)
	vec2::vec2(float X, float Y) :
		x(X), y(Y) {}

	// constructor : from one value, (a,a,a)
	vec2::vec2(float a) :
		x(a), y(a) {}

	// constructor : from an array of float[3]
	vec2::vec2(float *v) :
		x(v[0]), y(v[1]) {}

	// constructor : from another vector
	vec2::vec2(const vec2 &v) :
		x(v.x), y(v.y) {}

	// destructor
	vec2::~vec2() {}

	float vec2::total(void)
	{
		// addition of all values
		return x + y;
	}

	vec2 vec2::negated(void)
	{
		// negative vector
		return vec2(-x, -y);
	}

	void vec2::asArray(float *arr)
	{
		// values of vector to array
		arr[0] = x;
		arr[1] = y;
	}

	float vec2::magnitude(void)
	{
		// magnitude of vector
		return sqrt(magnitudeSqr());
	}

	float vec2::magnitudeSqr(void)
	{
		// magnitude squared of vector
		return (x * x) + (y * y);
	}

	vec2 vec2::normal(void)
	{
		// unit vector
		return *this / this->magnitude();
	}

	vec2 vec2::direction(void)
	{
		// angles between (1,1,1) and this vector on each axis
		vec2 temp = this->normal();
		temp((float)(acos(temp.x) * RADTODEG),
			(float)(acos(temp.y) * RADTODEG));
		return temp;
	}

	float vec2::distancebetween(vec2 v)
	{
		// distance between this vector and v
		vec2 temp(x - v.x, y - v.y);
		return sqrt(temp * temp);
	}

	float vec2::anglebetween(vec2 v)
	{
		// angle between this vector and v
		float temp = *this * v;
		temp /= magnitude() * v.magnitude();
		return acos(temp) * (float)(RADTODEG);
	}

	float vec2::dotproduct(vec2 v)
	{
		// dot product between this vector and vector v
		vec2 temp(x * v.x,
			y * v.y);
		return temp.total();
	}

	vec2 vec2::operator+ (vec2 v)
	{
		// add vector v to this vector
		vec2 temp(x + v.x,
			y + v.y);
		return temp;
	}

	void vec2::operator+= (vec2 v)
	{
		// add vector v to this vector
		x += v.x;
		y += v.y;
	}

	vec2 vec2::operator- (vec2 v)
	{
		// subtract vector v from this vector
		vec2 temp(x - v.x,
			y - v.y);
		return temp;
	}

	void vec2::operator-= (vec2 v)
	{
		// subtract vector v from this vector
		x -= v.x;
		y -= v.y;
	}

	vec2 vec2::operator* (float f)
	{
		// multiply this vector by f
		vec2 temp(x * f,
			y * f);
		return temp;
	}

	void vec2::operator*= (float f)
	{
		// multiply this vector by f
		x *= f;
		y *= f;
	}

	vec2 vec2::operator/ (float f)
	{
		// divide this vector by f

		// Check for division by zero
		// Return an empty vector
		if (f == 0)
		{
			Logger->AddLog("vec2 vec2::operator/ (float) : Divide by zero! Returning zero vector");
			return vec2(0.0);
		}

		vec2 temp(x / f,
			y / f);
		return temp;
	}

	void vec2::operator/= (float f)
	{
		// divide this vector by f

		// Check for division by zero
		// Return an empty vector
		if (f == 0)
		{
			Logger->AddLog("void vec2::operator/= (float) : Divide by zero! Returning zero vector");
			x = y = 0;
			return;
		}

		x /= f;
		y /= f;
	}

	bool vec2::operator== (vec2 v)
	{
		return (x == v.x) && (y == v.y);
	}

	bool vec2::operator!= (vec2 v)
	{
		return (x != v.x) || (y != v.y);
	}

	bool vec2::operator> (vec2 v)
	{
		return magnitude() > v.magnitude();
	}

	bool vec2::operator>= (vec2 v)
	{
		return magnitude() >= v.magnitude();
	}

	bool vec2::operator< (vec2 v)
	{
		return magnitude() < v.magnitude();
	}

	bool vec2::operator<= (vec2 v)
	{
		return magnitude() <= v.magnitude();
	}

	float vec2::operator* (vec2 v)
	{
		// dot product between this vector and vector v
		return dotproduct(v);
	}
	void vec2::operator() (float X, float Y)
	{
		x = X; y = Y;
	}

	vec2 operator- (vec2 v)
	{
		return v.negated();
	}

	float vec2::operator[] (int a)
	{
		switch (a)
		{
		case 0: return x;
		case 1: return y;
		default: return 0;
		}
	}

	ostream& operator<< (ostream &os, vec2 &v)
	{
		// output vector contents to console in the format: x=1 y=2
		os << "x=" << v.x
			<< " y=" << v.y;
		return os;
	}

	_Logger& operator<< (_Logger &logger, vec2 &v)
	{
		// output vector contents to Logger in the format: x=1 y=2
		*Logger << "x=" << v.x
			<< " y=" << v.y;
		return logger;
	}

	vec2 detectzero(vec2 v)
	{
		return vec2(::detectzero(v.x), ::detectzero(v.y));
	}

} // namespace GeorgeLib //